{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Chapter 1 - The Machine Learning landscape**\n",
    "\n",
    "_This is the code used to generate some of the fiures in chapter 1._\n",
    "\n",
    "# Code example 1-1\n",
    "\n",
    "Although Python 2.x may work, it is deprecated so we strongly recommend you use Python 3 instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Python ≥ 3.5 is required\n",
    "import sys\n",
    "assert sys.version_info >= (3, 5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Scikit-Learn >= 0.20 is required\n",
    "import sklearn\n",
    "assert sklearn.__version__ >= \"0.20\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function just merges the OECD's life statisfaction data and the IMF's GDP per capita data. It's a bit too long and boring and it's not specific to Machine Learning, which is why I left it out of the book."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def prepare_country_stats(oecd_bli, gdp_per_capita):\n",
    "    oecd_bli = oecd_bli[oecd_bli[\"INEQUALITY\"] == \"TOT\"]\n",
    "    oecd_bli = oecd_bli.pivot(index=\"Country\", columns=\"Indicator\", values=\"Value\")\n",
    "    gdp_per_capita.rename(columns={\"2015\": \"GDP per capita\"}, inplace=True)\n",
    "    gdp_per_capita.set_index(\"Country\", inplace=True)\n",
    "    full_country_stats = pd.merge(left=oecd_bli, right=gdp_per_capita,\n",
    "                                  left_index=True, right_index=True)\n",
    "    full_country_stats.sort_values(by=\"GDP per capita\", inplace=True)\n",
    "    remove_indices = [0, 1, 6, 8, 33, 34, 35]\n",
    "    keep_indices = list(set(range(36)) - set(remove_indices))\n",
    "    return full_country_stats[[\"GDP per capita\", 'Life satisfaction']].iloc[keep_indices]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The code in the book expects the data files to be located in the current directory. I just tweaked it here to fetch the files in datasets/lifesat."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "datapath = os.path.join(\"datasets\", \"lifesat\", \"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# To plot pretty figures directly within Jupyter\n",
    "%matplotlib inline\n",
    "import matplotlib as mpl\n",
    "mpl.rc('axes', labelsize=14)\n",
    "mpl.rc('xtick', labelsize=12)\n",
    "mpl.rc('ytick', labelsize=12)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading oecd_bli_2015.csv\n"
     ]
    },
    {
     "ename": "URLError",
     "evalue": "<urlopen error [Errno 111] Connection refused>",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mConnectionRefusedError\u001b[0m                    Traceback (most recent call last)",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:1354\u001b[0m, in \u001b[0;36mAbstractHTTPHandler.do_open\u001b[0;34m(self, http_class, req, **http_conn_args)\u001b[0m\n\u001b[1;32m   1353\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 1354\u001b[0m     \u001b[43mh\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mreq\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_method\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreq\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mselector\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreq\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1355\u001b[0m \u001b[43m              \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreq\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhas_header\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mTransfer-encoding\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1356\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err: \u001b[38;5;66;03m# timeout error\u001b[39;00m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:1256\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1255\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Send a complete request to the server.\"\"\"\u001b[39;00m\n\u001b[0;32m-> 1256\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:1302\u001b[0m, in \u001b[0;36mHTTPConnection._send_request\u001b[0;34m(self, method, url, body, headers, encode_chunked)\u001b[0m\n\u001b[1;32m   1301\u001b[0m     body \u001b[38;5;241m=\u001b[39m _encode(body, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbody\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m-> 1302\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mendheaders\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:1251\u001b[0m, in \u001b[0;36mHTTPConnection.endheaders\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1250\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m CannotSendHeader()\n\u001b[0;32m-> 1251\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_output\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage_body\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:1011\u001b[0m, in \u001b[0;36mHTTPConnection._send_output\u001b[0;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[1;32m   1010\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_buffer[:]\n\u001b[0;32m-> 1011\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1013\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m message_body \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m   1014\u001b[0m \n\u001b[1;32m   1015\u001b[0m     \u001b[38;5;66;03m# create a consistent interface to message_body\u001b[39;00m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:951\u001b[0m, in \u001b[0;36mHTTPConnection.send\u001b[0;34m(self, data)\u001b[0m\n\u001b[1;32m    950\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mauto_open:\n\u001b[0;32m--> 951\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    952\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:1418\u001b[0m, in \u001b[0;36mHTTPSConnection.connect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m   1416\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnect to a host on a given (SSL) port.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m-> 1418\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   1420\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tunnel_host:\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/http/client.py:922\u001b[0m, in \u001b[0;36mHTTPConnection.connect\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    921\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Connect to the host and port specified in __init__.\"\"\"\u001b[39;00m\n\u001b[0;32m--> 922\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msock \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_create_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    923\u001b[0m \u001b[43m    \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhost\u001b[49m\u001b[43m,\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msource_address\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    924\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msock\u001b[38;5;241m.\u001b[39msetsockopt(socket\u001b[38;5;241m.\u001b[39mIPPROTO_TCP, socket\u001b[38;5;241m.\u001b[39mTCP_NODELAY, \u001b[38;5;241m1\u001b[39m)\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/socket.py:808\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address)\u001b[0m\n\u001b[1;32m    807\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 808\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[1;32m    809\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[1;32m    810\u001b[0m     \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/socket.py:796\u001b[0m, in \u001b[0;36mcreate_connection\u001b[0;34m(address, timeout, source_address)\u001b[0m\n\u001b[1;32m    795\u001b[0m     sock\u001b[38;5;241m.\u001b[39mbind(source_address)\n\u001b[0;32m--> 796\u001b[0m \u001b[43msock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43msa\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    797\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n",
      "\u001b[0;31mConnectionRefusedError\u001b[0m: [Errno 111] Connection refused",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[0;31mURLError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[14], line 8\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDownloading\u001b[39m\u001b[38;5;124m\"\u001b[39m, filename)\n\u001b[1;32m      7\u001b[0m url \u001b[38;5;241m=\u001b[39m DOWNLOAD_ROOT \u001b[38;5;241m+\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdatasets/lifesat/\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m+\u001b[39m filename\n\u001b[0;32m----> 8\u001b[0m \u001b[43murllib\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlretrieve\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdatapath\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mfilename\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:247\u001b[0m, in \u001b[0;36murlretrieve\u001b[0;34m(url, filename, reporthook, data)\u001b[0m\n\u001b[1;32m    230\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    231\u001b[0m \u001b[38;5;124;03mRetrieve a URL into a temporary location on disk.\u001b[39;00m\n\u001b[1;32m    232\u001b[0m \n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    243\u001b[0m \u001b[38;5;124;03mdata file as well as the resulting HTTPMessage object.\u001b[39;00m\n\u001b[1;32m    244\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    245\u001b[0m url_type, path \u001b[38;5;241m=\u001b[39m _splittype(url)\n\u001b[0;32m--> 247\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m contextlib\u001b[38;5;241m.\u001b[39mclosing(\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m) \u001b[38;5;28;01mas\u001b[39;00m fp:\n\u001b[1;32m    248\u001b[0m     headers \u001b[38;5;241m=\u001b[39m fp\u001b[38;5;241m.\u001b[39minfo()\n\u001b[1;32m    250\u001b[0m     \u001b[38;5;66;03m# Just return the local path and the \"headers\" for file://\u001b[39;00m\n\u001b[1;32m    251\u001b[0m     \u001b[38;5;66;03m# URLs. No sense in performing a copy unless requested.\u001b[39;00m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:222\u001b[0m, in \u001b[0;36murlopen\u001b[0;34m(url, data, timeout, cafile, capath, cadefault, context)\u001b[0m\n\u001b[1;32m    220\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m    221\u001b[0m     opener \u001b[38;5;241m=\u001b[39m _opener\n\u001b[0;32m--> 222\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mopener\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:525\u001b[0m, in \u001b[0;36mOpenerDirector.open\u001b[0;34m(self, fullurl, data, timeout)\u001b[0m\n\u001b[1;32m    522\u001b[0m     req \u001b[38;5;241m=\u001b[39m meth(req)\n\u001b[1;32m    524\u001b[0m sys\u001b[38;5;241m.\u001b[39maudit(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124murllib.Request\u001b[39m\u001b[38;5;124m'\u001b[39m, req\u001b[38;5;241m.\u001b[39mfull_url, req\u001b[38;5;241m.\u001b[39mdata, req\u001b[38;5;241m.\u001b[39mheaders, req\u001b[38;5;241m.\u001b[39mget_method())\n\u001b[0;32m--> 525\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mreq\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    527\u001b[0m \u001b[38;5;66;03m# post-process response\u001b[39;00m\n\u001b[1;32m    528\u001b[0m meth_name \u001b[38;5;241m=\u001b[39m protocol\u001b[38;5;241m+\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m_response\u001b[39m\u001b[38;5;124m\"\u001b[39m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:542\u001b[0m, in \u001b[0;36mOpenerDirector._open\u001b[0;34m(self, req, data)\u001b[0m\n\u001b[1;32m    539\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m result\n\u001b[1;32m    541\u001b[0m protocol \u001b[38;5;241m=\u001b[39m req\u001b[38;5;241m.\u001b[39mtype\n\u001b[0;32m--> 542\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_chain\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mhandle_open\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprotocol\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprotocol\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\n\u001b[1;32m    543\u001b[0m \u001b[43m                          \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m_open\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreq\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    544\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m result:\n\u001b[1;32m    545\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m result\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:502\u001b[0m, in \u001b[0;36mOpenerDirector._call_chain\u001b[0;34m(self, chain, kind, meth_name, *args)\u001b[0m\n\u001b[1;32m    500\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m handler \u001b[38;5;129;01min\u001b[39;00m handlers:\n\u001b[1;32m    501\u001b[0m     func \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mgetattr\u001b[39m(handler, meth_name)\n\u001b[0;32m--> 502\u001b[0m     result \u001b[38;5;241m=\u001b[39m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    503\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m result \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    504\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m result\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:1397\u001b[0m, in \u001b[0;36mHTTPSHandler.https_open\u001b[0;34m(self, req)\u001b[0m\n\u001b[1;32m   1396\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mhttps_open\u001b[39m(\u001b[38;5;28mself\u001b[39m, req):\n\u001b[0;32m-> 1397\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdo_open\u001b[49m\u001b[43m(\u001b[49m\u001b[43mhttp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mHTTPSConnection\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreq\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m   1398\u001b[0m \u001b[43m        \u001b[49m\u001b[43mcontext\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_context\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcheck_hostname\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_check_hostname\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[0;32m~/programs/anaconda3/envs/tf2/lib/python3.8/urllib/request.py:1357\u001b[0m, in \u001b[0;36mAbstractHTTPHandler.do_open\u001b[0;34m(self, http_class, req, **http_conn_args)\u001b[0m\n\u001b[1;32m   1354\u001b[0m         h\u001b[38;5;241m.\u001b[39mrequest(req\u001b[38;5;241m.\u001b[39mget_method(), req\u001b[38;5;241m.\u001b[39mselector, req\u001b[38;5;241m.\u001b[39mdata, headers,\n\u001b[1;32m   1355\u001b[0m                   encode_chunked\u001b[38;5;241m=\u001b[39mreq\u001b[38;5;241m.\u001b[39mhas_header(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mTransfer-encoding\u001b[39m\u001b[38;5;124m'\u001b[39m))\n\u001b[1;32m   1356\u001b[0m     \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err: \u001b[38;5;66;03m# timeout error\u001b[39;00m\n\u001b[0;32m-> 1357\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m URLError(err)\n\u001b[1;32m   1358\u001b[0m     r \u001b[38;5;241m=\u001b[39m h\u001b[38;5;241m.\u001b[39mgetresponse()\n\u001b[1;32m   1359\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n",
      "\u001b[0;31mURLError\u001b[0m: <urlopen error [Errno 111] Connection refused>"
     ]
    }
   ],
   "source": [
    "# Download the data\n",
    "import urllib.request\n",
    "DOWNLOAD_ROOT = \"https://raw.githubusercontent.com/ageron/handson-ml2/master/\"\n",
    "os.makedirs(datapath, exist_ok=True)\n",
    "for filename in (\"oecd_bli_2015.csv\", \"gdp_per_capita.csv\"):\n",
    "    print(\"Downloading\", filename)\n",
    "    url = DOWNLOAD_ROOT + \"datasets/lifesat/\" + filename\n",
    "    urllib.request.urlretrieve(url, datapath + filename)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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5RU1btxYn376qfz8fstQjRs31siRIzVy5EiNGDFCN910k0aMGOHWYgEAANzBpSNA+/fv14ABA+zhR5Ly8/Pt/+7Ro4cGDRqkuXPnXn2FAAAAbubyXWC1a9e2/7tGjRrKyMhwmN6yZUvt27fP5cIAAAA8xaUA1KBBA504ccL+vmnTptqyZYtDn+TkZNWoUePqqgMAAPAAlwJQ165dlZSUZH8/dOhQ7dy5UxMnTtTq1as1depUffrpp4qLi3NboQAAAO7i0m3wiYmJevHFF/Xvf/9b0dHROnv2rHr06KGdO3fKZrPJGKPGjRsrISFB0dHRnqjb47gNHgCAisfjg6Fe7sKFC/roo4906NAhRUdHa8iQIRX6FBgBCACAisetg6H27t1b48aN05gxYyRJGzZsUOPGjdWoUSN7nypVquiOO+64yrIBAAA8z6lrgBITE3XkyBH7+169emnZsmUeKgkAAMCznApAoaGhDre5M4A8AACoyJw6BRYbG6sVK1aoYcOGqlevniRp165dWr58+RXnLTxtBgAA4Cucugh6y5YtGjJkiNLT0+13eRUOeloSBkMFAADlza0XQXfq1EkHDx7Utm3blJqaqnHjxmno0KEaOnSo2woGAAAoL04PhhocHKw+ffpIksaNG6e2bdtq7NixHisMAADAU1waDf7ixYvurgMAAKDcuBSASrJ582Z98sknqlatmsaPH6/IyEh3Lh4AAMAtXBoL7LHHHlNQUJAyMzPtbe+99566d++uOXPm6Omnn9YNN9yg1NRUtxUKAADgLi4FoISEBPXq1UuhoaH2tunTpyskJETLly/XSy+9pIyMDM2bN89thQIAALiLSwHo2LFjat68uf39gQMH9P333+uhhx7SXXfdpccee0wDBw7UmjVr3FYoAACAu7gUgM6ePauaNWva32/cuFE2m00333yzve26667TiRMnrr5CAAAAN3MpAF1zzTX6/vvv7e8/++wz1axZUzfeeKO9LTs7W4GBgVdfIQAAgJu5dBdYjx49FB8fr4ULFyooKEgffvihbrnlFvn7+9v7HDx4UA0bNnRboQAAAO7i1FAYlzt48KA6dOig7OxsGWNUvXp1JSUlqU2bNpKktLQ0NWzYUBMmTNCiRYvcXnR5YCgMAAAqHrcOhXG5Zs2a6dtvv9X7778vSRo8eLAaN25sn3706FHdf//9Gj16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gswf//hHh/mfe+45Y7PZzL59++xtCxcuNJLM119/bW+7cOGCue6660zHjh0d5u/QoYO57rrrzIULF+xtmzZtMpLMokWLXFt5H/Dzzz8XaTtz5oypV6+e6dOnj72N7V++OnXqZKKiouzv2f7lY/DgwWbIkCFm7NixRQIQ+8AzCgPQu+++W2o/tr/vIgC5QUkB6MKFC6ZatWrmvvvuKzJPv379TPPmze3vV65caSSZzZs3O/Q7efKkkWSee+45e1vfvn1Ny5Ytiyzz+eefN5LMiRMnjDG//VehJDNnzpwifVu0aGFuuummMq1nRdCrVy/TokULYwzb3xsGDRpkmjRpYoxh+5eXFStWmFq1apnjx48XCUDsA89xJgCx/X0b1wB50KFDh5Sbm6vY2Ngi02JjY3Xw4EGdP39ekpScnCxJiomJceh3zTXXKDw83D69sG9Jy5Skffv2OSyzpL6XLrMyyMrK0o4dO9S6dWtJbP/ycPHiReXn5ystLU2LFi3S559/rscff1wS2788nDp1So888oheeOGFYscuZB943qRJkxQQEKDg4GD1799fGzdutE9j+/s2ApAHZWRkSJJCQ0OLTAsNDZUxRr/88ou9b2BgoGrUqFFs38JlFfYtaZmXfu6VPv/SZVYGkyZNUk5OjqZNmyaJ7V8e7r//flWpUkURERH685//rH/84x+67777JLH9y8P999+vli1b6k9/+lOx09kHnhMSEqKHH35YL7/8shISEjR//nwdP35cPXv21Oeffy6J7e/rGA2+HNhsNqemOdvPXX1LW0ZFM336dL3xxhtasGCBbrzxRodpbH/PefLJJ3Xvvffq1KlTWrVqlR544AHl5OToscces/dh+3vG+++/r1WrVmnnzp1XXBf2gfu1a9dO7dq1s7/v3r27hg0bppiYGE2ZMkX9+/e3T2P7+yaOAHlQWFiYJBWbsjMzM2Wz2VS7dm173/Pnz+vcuXPF9r00wYeFhZW4TOm/af9Kn1/cfxVURLNmzdKzzz6r5557Tg888IC9ne3veY0aNVL79u01cOBA/etf/9If//hHTZ06VWlpaWx/Dzp79qwmTZqkBx98UJGRkTp9+rROnz6tX3/9VZJ0+vRp5eTksA/KWe3atTV48GDt2bNHubm5bH8fRwDyoKZNm6patWrau3dvkWl79+5Vs2bNFBQUJOm/530v7/vTTz8pPT1dbdq0sbfFxMSUuExJ9r6F/1tS30uXWVHNmjVLM2fO1MyZM/Xkk086TGP7l7+OHTsqPz9fhw8fZvt7UHp6un7++WfNmzdPderUsb/i4+OVk5OjOnXq6Pe//z37wAvM/w2vabPZ2P6+zptXYFcWpd0GP2LECBMREWGys7PtbUePHjVVq1Y1jz/+uL0tIyPDBAUFmYkTJzrMP2fOnCK3QC5atMhIMklJSfa2CxcumNatW5tOnTo5zN+xY0fTpk0bk5+fb2/bvHmzkWT+9a9/ubzOvuCZZ54xksxTTz1VYh+2f/m6++67jZ+fn/35Jmx/z8jNzTUJCQlFXv379zdBQUEmISHB7N271xjDPihPmZmZpkGDBqZt27b2Nra/7yIAXYU1a9aYd99917z22mtGkhk+fLh59913zbvvvmtycnKMMb89BKtmzZomLi7OrFmzxvznP/8xbdq0KfUhWE8++aRJTEw0f/3rX01gYGCxD8Fq3bq1iYqKMm+88Yb58ssvzbBhw4p9CFZCQoIJCAgww4YNM19++aV54403TFRUVIV/CNbcuXONJDNgwIAiDyG79DZStr9n/OEPfzCPPvqoefvtt01iYqJ57733zMiRI40kM3nyZHs/tn/5Ku45QOwDzxg1apR5/PHHzbvvvmsSEhLMK6+8Ylq2bGkCAgLMl19+ae/H9vddBKCrEB0dbSQV+0pJSbH32759u+nTp4+pXr26CQ4ONrfeeqs5ePBgscucP3++adGihalatapp1KiRmTFjhvn111+L9Pvpp5/MmDFjTGhoqAkKCjKdO3d2+KO71BdffGE6d+5sgoKCTGhoqBkzZkyxDxKsSHr06FHitr/8wCbb3/1ee+010717dxMeHm4CAgJM7dq1TY8ePcyKFSuK9GX7l5/iApAx7ANPmDNnjmnbtq0JCQkx/v7+pm7dumbYsGFm69atRfqy/X2TzZj/O2EJAABgEVwEDQAALIcABAAALIcABAAALIcABAAALIcABAAALIcABAAALIcABAAALIcABAAALIcABAAVWM+ePWWz2bxdBlDhEIAAC9i1a5cmTpyo6667TsHBwapataquueYa9evXT3//+9+VkZFRZB6bzebwqlatmurXr69u3brpscce0+7du4v9rCNHjhSZt2rVqoqKitLo0aO1Z88eT6+u5S1btkw2m03Lli3zdimAz2IoDKASu3jxoqZMmaJ58+YpICBAcXFxiomJUfXq1XXq1Cl9/fXX+u6771SrVi0dPnxY4eHh9nltNpvCwsL0wAMPSJIuXLig9PR07dixQ9u3b5ckjR8/XosWLVJgYKB9viNHjqhJkyZq2rSp7rrrLknS2bNnlZSUpE2bNikwMFDr16/X7373u3LcEpXXsWPHdO7cObVq1cretmzZMt1zzz1aunSpxo0b573iAB8W4O0CAHjOtGnTNG/ePLVv315vvfWWmjZtWqTPtm3bNGXKFJ0/f77ItPDwcM2cObNI+969ezVmzBi99tpr+vXXX7VixYoifZo1a1Zk3qeeekrPPfecpk2bpoSEBJfXC//VqFEjb5cAVEzeHYsVgKf88MMPxt/f30RERJi0tLRS+168eNHk5+c7tEkyLVu2LHGeU6dOmYiICCPJbNmyxd6ekpJiJJn+/fsXmeenn34ykoodsfxyM2bMMJJMQkKCeeWVV8x1111nAgMDTVRUlHniiSdMbm5usfPt3r3bjBw50tSvX99UqVLFNGrUyDzwwAMmPT3doV9hnWPHjjXfffedGTZsmAkLCzOSTEpKyhXr+/nnn82jjz5qWrRoYQIDA02dOnVMp06dzNy5cx36LVmyxNxyyy0mOjra3q9fv35m/fr1RZaZkJBgJJkZM2aYr776ysTFxZkaNWqYOnXqmFGjRpnjx48XmadHjx7m0v8rHzt2rJFU7KvQ9u3bzaRJk0zr1q1NcHCwCQoKMm3atDFz5swpduRxoDLiCBBQSS1btkwFBQW67777HE5tFcdms8nf379My69bt64mTpyoZ555Rm+//bY6dux4xXlcuVh33rx5SkxM1MiRIzV48GCtWbNGL7zwgnbu3KlPP/3UYZkff/yxRowYIX9/f91yyy2KiorSt99+q3/+85/6/PPPtWXLFtWpU8dh+QcPHlTnzp3VunVrjR07VpmZmapatWqpNR04cEC9evVSamqqunXrpltvvVU5OTlKTk7Wc889p0cffdTed9KkSbr++uvVt29f1a1bV6mpqfrwww/Vt29f/ec//9HQoUOLLD8pKUlz5szRoEGD9NBDD2nHjh2Kj4/Xxo0btW3bNtWrV6/E2m699VadPn1aH330kYYOHaq2bdsW6fPqq69q1apViouL08CBA3Xu3DklJiZq6tSp2rZtm95///1S1x+oFLydwAB4Rq9evYykYo80OENXOAJkjDHr1q0zkkz37t3tbaUdAZo2bZqRZHr27HnFzy88AhQUFGSSk5Pt7RcuXDA33XSTkWSWL19ub09PTzfBwcGmYcOG5ujRow7LevPNN40k88ADDxSpU5KZPn36Feu5VMeOHY0k88orrxSZdvlRmsOHDxfpc/LkSRMZGWmaN2/u0F54BEiSWbx4scO0WbNmGUlm/PjxDu2XHwEyxpilS5caSWbp0qXF1n/kyJEiR/wuXrxoxo8fbySZjRs3FjsfUJlwFxhQSf3000+SpMjIyCLT1q9fr5kzZzq8Nm7cWObPKFx2enp6kWkHDx60L/uxxx5Tt27d9NxzzykoKEjPP/+8059x9913q3Xr1vb3AQEB9vlff/11e/vy5cuVnZ2tOXPmFLkuZtSoUbrhhhv01ltvFVl+/fr19dRTTzldz7Zt27R161bFxcXpD3/4Q5HpDRs2dHjfpEmTIn2uueYa3X777Tpw4ICOHj1aZHrLli01fvx4h7bJkyerbt26io+P16+//up0vcWJjo4ucsTPZrNp0qRJkqS1a9de1fKBioBTYEAlZUq5wXP9+vV67rnnHNqCgoLUrVs3t33GoUOHNGvWLElSlSpVVK9ePY0ePVpPPPGEYmJinP6M7t27F2lr3769qlWrpl27dtnbkpKS7P978ODBIvOcP39e6enpSk9PdzgleP3111/xlNeltm7dKknq16+fU/0PHz6sOXPmaP369UpNTVVeXp7D9JMnTyo6OtqhrWvXrkVOF1arVk033nijPvvsM/3www9q06aN0zVf7tdff9U///lPvfXWW9q/f7/Onj3rsC9Pnjzp8rKBioIABFRS9erV0/79+5WamqqWLVs6THv22Wf17LPPSvrvLdOu+PHHHyX9dj3Q5fr376/PPvvMpeVeKiIiosT21NRU+/vMzExJ0sKFC0tdXk5OjkMAKu16muKcPn1aktSgQYMr9j148KA6duyo7Oxs9erVS0OGDFFwcLD8/PyUmJior776qkggkkpe58Jas7KyylTz5e644w6tWrVKLVq00MiRIxUREaEqVaro9OnTmj9/frE1AZUNAQiopH73u9/pq6++UkJCgnr37u2Rz0hMTJQkdejQwSPLl6RTp06V2B4SEmJ/HxwcLOm3W/TLcnSkrBdm165dW5IcwldJ/vd//1e//PKLVq5cqd///vcO0yZOnKivvvqq2PlKWueff/5ZkhzWu6y2bdumVatWqX///lq9erXDqbCkpCTNnz/f5WUDFQnXAAGV1NixY+Xn56dXXnml2Gt0rlZaWppefvllSdKdd97p9uUX+n//7/8Vadu+fbtyc3Md7nDq1KmTJGnz5s0eq0WS/W63L7744op9Dx06JEm65ZZbHNovXryoTZs2lTjfpk2bipxezM3N1TfffKNq1aqpRYsWpX5uYagpKCgosaZBgwYVuQ6ouG0NVFYEIKCSatmypf7yl7/o1KlTuvnmm+0/fJcrPKVTFsnJyerXr59OnTqlcePGqX379ldZbclWrFihffv22d/n5+frySeflPRbyCt0zz33qFatWpo2bZpD/0Lnzp2zXyd0NTp06KCOHTtqw4YNevXVV4tMv/TIUOG1PZdfYP7iiy8qOTm5xM/4/vvv9dprrzm0/fWvf1VaWppGjRp1xWuWQkNDJUknTpwoMq2kmvbt26c5c+aUulygMuEUGFCJvfDCC7pw4YLmz5+vli1bqkePHoqNjbUPhbFr1y5t375dwcHBio2NLTJ/enq6/WnO+fn5ysjI0DfffKNt27ZJku69994rXnNztfr27avOnTvrzjvvVGhoqNasWaPk5GT179/fPtSGJPsdUsOHD9f111+vAQMGqFWrVjp//ryOHj2qr776Sr/73e/ccl3SypUr1bNnT/3xj3/UihUr1KVLF50/f1779u3Tzp077WOrTZw4UUuXLtVtt92mkSNHKiwsTElJSdqxY4cGDRqk1atXF7v8fv366f7779fq1avVqlUr7dixQ59//rmioqKcuoOuS5cuqlatmv7+978rOzvbfo3WE088oY4dO6pjx45655139OOPP6pz5846duyYPv74Yw0aNEjvvffeVW8foELw7l34AMrD9u3bzb333mtatGhhatSoYapUqWLq1atn+vbta/72t78V+6RoXfYU4cDAQBMREWG6du1qHnvsMbN79+5iP6u05wCVxaVPgn755ZftT4Ju2LCheeKJJ8y5c+eKnW///v1mwoQJJjo62lStWtXUqVPHxMTEmIceeshs3bq1SJ1jx451qb6ffvrJPPzww+baa681VatWNaGhoaZTp07mb3/7m0O/hIQE07VrV1OrVi1Tu3ZtM3DgQPPNN984rN+lfXXJk6C7d+9uqlevbmrXrm3uvPNOc+zYsSJ1FPccIGOMWb16tenQoYOpVq1akSdBnzp1yowfP95ERkaaoKAgExMTYxYuXGgOHz58VdsEqEgYDBWAT5o5c6ZmzZqlhIQE9ezZ09vllIvExET16tVLM2bMKHYMNgDuwzVAAADAcghAAADAcghAAADAcrgGCAAAWA5HgAAAgOUQgAAAgOUQgAAAgOUQgAAAgOUQgAAAgOUQgAAAgOUQgAAAgOUQgAAAgOX8f4zgvB8mtjecAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[5.76666667]]\n"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import sklearn.linear_model\n",
    "import sklearn.neighbors\n",
    "\n",
    "#Load the data\n",
    "oecd_bli = pd.read_csv(\"datasets/lifesat/oecd_bli_2015.csv\", thousands=\",\")\n",
    "gdp_per_capita = pd.read_csv(\"datasets/lifesat/gdp_per_capita.csv\", thousands=\",\", delimiter=\"\\t\", encoding=\"latin1\", na_values=\"n/a\")\n",
    "\n",
    "#prepar the data\n",
    "country_stats = prepare_country_stats(oecd_bli, gdp_per_capita)\n",
    "X = np.c_[country_stats[\"GDP per capita\"]]\n",
    "Y = np.c_[country_stats[\"Life satisfaction\"]]\n",
    "\n",
    "# Visualize the data\n",
    "country_stats.plot(kind='scatter', x=\"GDP per capita\", y='Life satisfaction')\n",
    "plt.show()\n",
    "\n",
    "# Select a linear model\n",
    "# model = sklearn.linear_model.LinearRegression()\n",
    "model = sklearn.neighbors.KNeighborsRegressor(n_neighbors=3)\n",
    "\n",
    "# Train the model\n",
    "model.fit(X, Y)\n",
    "\n",
    "# Make a prediction for cygrus\n",
    "X_new = [[22587]] # Cyprus' GDP per capita\n",
    "print(model.predict(X_new)) # outputs"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tf2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
